NestJS API Versioning With Swagger
- aliases
- No value
- tags
- nestjs
- description
- No value
- links
- Nest.js ๐ฑ https://chatgpt.com/s/dr_6826d5e83ca481918153c428cd2e2645
- status
- ai response
- project
- false
- area
- true
- resource
- false
- title
- NestJS API Versioning With Swagger
- created
- 2025-05-16T15:03:41
- updated
- 2025-05-16T15:06:41
Written by Chat GPT Deep Research
NestJS API ๋ฒ์ ๋๊ณผ Swagger ์ฐ๋
NestJS๋ REST API๋ฅผ ํจ์จ์ ์ผ๋ก ๊ตฌ์ถํ ์ ์๋๋ก API ๋ฒ์ ๊ด๋ฆฌ(Versioning) ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ๋ํ @nestjs/swagger ๋ชจ๋์ ์ฌ์ฉํ๋ฉด API ๋ฌธ์๋ฅผ ์์ฝ๊ฒ ์๋ ์์ฑํ ์ ์์ต๋๋ค. ์ด ๊ธ์์๋ URI ๊ธฐ๋ฐ์ API ๋ฒ์ ๋์ NestJS์์ ๊ตฌํํ๊ณ Swagger(OpenAPI) ๋ฌธ์ํ์ ํตํฉํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ค๋ฌด ์์ ๋ฅผ ํตํด ๋จ์ผ Swagger ๋ฌธ์๋ก ๋ชจ๋ ๋ฒ์ ์ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ๊ณผ, ๋ค์ค Swagger ๋ฌธ์๋ก ๋ฒ์ ๋ณ(๋๋ ๋ชจ๋๋ณ)๋ก ๋ฌธ์๋ฅผ ๋ถ๋ฆฌํ๋ ๋ ๊ฐ์ง ์ ๋ต์ ๊ตฌํํ๊ณ ๋น๊ตํด๋ณด๊ฒ ์ต๋๋ค.
URI ๊ธฐ๋ฐ API ๋ฒ์ ๊ด๋ฆฌ ์ค์ (main.ts)
NestJS์์๋ ๊ฐ๋จํ ์ค์ ์ผ๋ก URI์ ๋ฒ์ ์ ๋ณด๋ฅผ ํฌํจ์ํฌ ์ ์์ต๋๋ค. URI ๋ฒ์ ๊ด๋ฆฌ๋ URL ๊ฒฝ๋ก์ /v1, /v2์ฒ๋ผ ๋ฒ์ ์ธ๊ทธ๋จผํธ๋ฅผ ์ถ๊ฐํ์ฌ ๋ฒ์ ์ ๊ตฌ๋ถํ๋ ๋ฐฉ์์
๋๋ค. ์ฐ์ main.ts ๋ถํธ์คํธ๋ฉ ํ์ผ์์ ๋ฒ์ ๊ด๋ฆฌ ๊ธฐ๋ฅ์ ํ์ฑํํด์ผ ํฉ๋๋ค. Nest ์ ํ๋ฆฌ์ผ์ด์
์ธ์คํด์ค์ ๋ํด app.enableVersioning()์ ํธ์ถํ๋ฉฐ, type: VersioningType.URI ์ต์
์ ์ง์ ํ๋ฉด URI ๊ธฐ๋ฐ ๋ฒ์ ๋์ด ์ ์ฉ๋ฉ๋๋ค.
ํนํ ์ค์ํ ์ ์ Swagger ๋ฌธ์๋ฅผ ์ค์ ํ๊ธฐ ์ ์ ๋จผ์ enableVersioning์ ํธ์ถํด์ผ ํ๋ค๋ ๊ฒ์
๋๋ค. ์ด๋ NestJS Swagger ๋ชจ๋์ ์ด์์์๋ ๊ฐ์กฐ๋ ๋ถ๋ถ์ผ๋ก, ์์๊ฐ ๋ฐ๋๋ฉด Swagger๊ฐ ๋ฒ์ ์ด ๋ถ์ ๊ฒฝ๋ก๋ค์ ์ธ์ํ์ง ๋ชปํ ์ ์์ต๋๋ค. ๋ค์์ main.ts์ ์์ ์ฝ๋์
๋๋ค:
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { VersioningType } from '@nestjs/common';
import { setupSwagger } from './setupSwagger'; // Swagger ์ค์ ํจ์ import
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// (์ค์) Swagger ์ค์ ์ ์ API ๋ฒ์ ๊ด๋ฆฌ ํ์ฑํ
app.enableVersioning({ type: VersioningType.URI });
// Swagger ๋ฌธ์ ์ค์
setupSwagger(app);
await app.listen(3000);
}
bootstrap();
์ ์ฝ๋์์ app.enableVersioning({ type: VersioningType.URI }) ํ ์ค๋ก ์ ์ญ์ ์ธ URI ๋ฒ์ ๊ด๋ฆฌ๊ฐ ํ์ฑํ๋ฉ๋๋ค. ์ด์ ์ปจํธ๋กค๋ฌ๋ ๋ผ์ฐํธ์ ๋ฒ์ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋ฌ๋ฉด ์์ฒญ ๊ฒฝ๋ก์ ํด๋น ๋ฒ์ ์ด ์๋์ผ๋ก ์ถ๊ฐ๋ฉ๋๋ค (์: /v1/..., /v2/...).
๋ฒ์ ๋ณ ์ปจํธ๋กค๋ฌ ๊ตฌํ (์: ReservationV2Controller)
์ด์ ํน์ ์ปจํธ๋กค๋ฌ์ ๋ฒ์ ์ ์ง์ ํ์ฌ ๋ฒ์ ์ ๋ฐ๋ผ ๋ค๋ฅธ ๋์์ ํ๋๋ก ๊ตฌ์ฑํ ์ ์์ต๋๋ค. NestJS์์๋ ์ปจํธ๋กค๋ฌ๋ ๊ฐ๋ณ ๊ฒฝ๋ก ํธ๋ค๋ฌ์ @Version() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋, ์ปจํธ๋กค๋ฌ ๋ฐ์ฝ๋ ์ดํฐ์ { version: '๊ฐ' } ์ต์
์ ์ค์ ํด๋น ๋ฒ์ ์์๋ง ๋์ํ๋๋ก ๋ง๋ค ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด v2 ๋ฒ์ ์ API ์๋ํฌ์ธํธ๋ฅผ ๋ด๋นํ๋ ReservationV2Controller๋ฅผ ๊ตฌํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
// reservation.v2.controller.ts
import { Controller, Get, Post, Param } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
@Controller({ path: 'reservations', version: '2' })
@ApiTags('Reservations')
export class ReservationV2Controller {
@Get()
@ApiOperation({ summary: '๋ชจ๋ ์์ฝ ๋ชฉ๋ก ์กฐํ (v2)' })
findAllV2() {
// ์์ฝ ๋ชฉ๋ก ์กฐํ v2 ๋ก์ง...
}
@Get(':id')
@ApiOperation({ summary: 'ID๋ก ์์ฝ ์กฐํ (v2)' })
findByIdV2(@Param('id') id: string) {
// ํน์ ID ์์ฝ ์กฐํ v2 ๋ก์ง...
}
@Post()
@ApiOperation({ summary: '์ ์์ฝ ์์ฑ (v2)' })
createV2() {
// ์์ฝ ์์ฑ v2 ๋ก์ง...
}
}
์ ์ฝ๋์์๋ @Controller({ path: 'reservations', version: '2' })๋ฅผ ํตํด ์ด ์ปจํธ๋กค๋ฌ์ ๋ชจ๋ ๊ฒฝ๋ก๊ฐ v2๋ก ๋ฒ์ ์ด ์ง์ ๋์์ต๋๋ค. ๋ฐ๋ผ์ ์๋ฅผ ๋ค์ด findAllV2() ๋ฉ์๋๋ GET ์์ฒญ์ผ๋ก /v2/reservations ๊ฒฝ๋ก๋ฅผ ์ฒ๋ฆฌํ๊ฒ ๋ฉ๋๋ค. (ReservationV1Controller์์๋ version์ '1'๋ก ์ง์ ํ๊ฑฐ๋ ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ฉํด /v1/reservations๋ฅผ ์ฒ๋ฆฌํ๋๋ก ๊ตฌํํ๋ฉด ๋ฉ๋๋ค.) ๊ฐ ์ปจํธ๋กค๋ฌ์ @ApiTags ๋ฑ์ ์ง์ ํ๋ฉด Swagger ๋ฌธ์์์ ํ๊ทธ๋ก ๊ตฌ๋ถํ ์๋ ์์ต๋๋ค.
์ด๋ ๊ฒ ๊ฐ ๋ฒ์ ๋ณ๋ก ๋ณ๋ ์ปจํธ๋กค๋ฌ๋ฅผ ๊ตฌ์ฑํ๋ฉด ๋ฒ์ ์์น์ ๋ฐ๋ฅธ ๋ณ๊ฒฝ ์ฌํญ์ ์๋ก์ด ์ปจํธ๋กค๋ฌ/๋ฉ์๋๋ก ๊ตฌํํ ์ ์์ด ๊ด๋ฆฌ๊ฐ ์ฉ์ดํฉ๋๋ค. NestJS๋ ์์ฒญ์ด ๋ค์ด์ฌ ๋ URI์ ๋ฒ์ ์ ๋ฐ๋ผ ํด๋น ๋ฒ์ ์ ์ง์ํ๋ ์ปจํธ๋กค๋ฌ์ ํธ๋ค๋ฌ๋ฅผ ์ฐพ์์ฃผ๋ฏ๋ก, ํด๋ผ์ด์ธํธ๋ /v1/... ๋๋ /v2/...์ ๊ฐ์ด ์ํ๋ ๋ฒ์ ์ ๋ช
์ํ์ฌ ํธ์ถํ๋ฉด ๋ฉ๋๋ค.
Swagger ์ค์ - ๋จ์ผ ๋ฌธ์ ํตํฉ
์ด์ Swagger๋ฅผ ์ค์ ํ์ฌ ๋ฒ์ ์ด ์ ์ฉ๋ API ์๋ํฌ์ธํธ๋ค์ ๋ฌธ์ํํด๋ณด๊ฒ ์ต๋๋ค. ์์ enableVersioning()์ ๋จผ์ ํธ์ถํ๊ธฐ ๋๋ฌธ์, ์ด์ Swagger ๋ฌธ์๋ฅผ ์์ฑํ๋ฉด ๊ฐ ๊ฒฝ๋ก์ ์๋์ผ๋ก ๋ฒ์ prefix๊ฐ ํฌํจ๋ ์ํ๋ก ์คํ์ด ๋ง๋ค์ด์ง๋๋ค. ํ ๊ฐ์ง ์ ๊ทผ ๋ฐฉ์์ **"๋จ์ผ Swagger ๋ฌธ์"**๋ฅผ ์์ฑํ์ฌ ๋ชจ๋ ๋ฒ์ ์ API๋ฅผ ํ๊บผ๋ฒ์ ๋ณด์ฌ์ฃผ๋ ๊ฒ์
๋๋ค. ์๊ท๋ชจ ์๋น์ค๋ API ๋ณ๊ฒฝ ๋ฒ์๊ฐ ํฌ์ง ์์ ๊ฒฝ์ฐ, ํ ๊ฐ์ Swagger UI์์ v1๊ณผ v2 ์๋ํฌ์ธํธ๋ฅผ ๋ชจ๋ ์ด๋ํ ์ ์์ด ํธ๋ฆฌํฉ๋๋ค.
๋จ์ผ ๋ฌธ์ ์ ๋ต์์๋ NestJS ์ ํ๋ฆฌ์ผ์ด์
์ ์ฒด๋ฅผ ๋์์ผ๋ก ํ ๋ฒ์ SwaggerModule.createDocument() ํธ์ถ๋ก ๋ฌธ์๋ฅผ ์์ฑํฉ๋๋ค. DocumentBuilder๋ฅผ ์ด์ฉํด ๊ธฐ๋ณธ์ ์ธ ์ ๋ณด(title, description, version ๋ฑ)๋ฅผ ์ค์ ํ๊ณ ๋ฌธ์๋ฅผ ๋ง๋ ๋ค, SwaggerModule.setup()์ผ๋ก Swagger UI ์๋ํฌ์ธํธ๋ฅผ ๋ฑ๋กํฉ๋๋ค. ์์ main.ts ์์์์๋ setupSwagger(app) ํจ์๋ฅผ ๋ณ๋๋ก ๋ถ๋ฆฌํ๋๋ฐ, ๊ทธ ๊ตฌํ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
// setupSwagger.ts
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { INestApplication } from '@nestjs/common';
export function setupSwagger(app: INestApplication) {
// Swagger ์ค์ ์์ฑ
const config = new DocumentBuilder()
.setTitle('Reservation API')
.setDescription('Reservation ์๋น์ค API ๋ฌธ์')
.setVersion('1.0')
.build();
// ์ ํ๋ฆฌ์ผ์ด์
์ ์ฒด๋ฅผ ๋์์ผ๋ก Swagger ๋ฌธ์ ์์ฑ (๋ชจ๋ ๋ฒ์ ํฌํจ)
const document = SwaggerModule.createDocument(app, config);
// Swagger UI ์๋ํฌ์ธํธ ์ค์ (์: http://localhost:3000/docs)
SwaggerModule.setup('docs', app, document);
}
์ ์ค์ ์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์
์ ๋ชจ๋ ๋ฑ๋ก๋ ๊ฒฝ๋ก๋ฅผ ์ค์บํ์ฌ OpenAPI ๋ฌธ์(document ๊ฐ์ฒด)๋ฅผ ์์ฑํฉ๋๋ค. ์ด ๋ฌธ์์๋ ํ์ฌ ์ ํ๋ฆฌ์ผ์ด์
์ ์กด์ฌํ๋ v1, v2 ๋ชจ๋ ๋ฒ์ ์ ์๋ํฌ์ธํธ๊ฐ ํฌํจ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด v1๊ณผ v2 ๋ ๊ฐ์ง ๋ฒ์ ์ reservations ๊ฒฝ๋ก๋ค์ด ๊ฐ๊ฐ /v1/reservations, /v2/reservations๋ก ๋ฌธ์ํ๋์ด ํ Swagger UI์์ ๋ชจ๋ ํ์ธํ ์ ์์ต๋๋ค. Swagger UI๋ ์ ์์์์ /docs ๊ฒฝ๋ก๋ก ์ ๊ณต๋๋ฏ๋ก, ๋ธ๋ผ์ฐ์ ์์ http://<์๋ฒ์ฃผ์>/docs๋ก ์ ์ํ๋ฉด ๋ฉ๋๋ค.
์ฐธ๊ณ : ์ ์ญ ๊ฒฝ๋ก(prefix)
app.setGlobalPrefix()๋ฅผ ์ฌ์ฉํด/api/v1ํ์์ผ๋ก ๊ฒฝ๋ก๋ฅผ ๊ตฌ์ฑํ๋ ๊ฒฝ์ฐ, Swagger ์ค์ ์ ์ ์ญ ํ๋ฆฌํฝ์ค๋ฅผ ๋ฌด์ํ๊ฑฐ๋ ๊ฒฝ๋ก๋ฅผ ์กฐ์ ํด์ผ ํฉ๋๋ค.SwaggerModule.createDocument์ ์ต์ ์ผ๋กignoreGlobalPrefix: true๋ฅผ ์ฃผ๋ฉด ์ ์ญ ํ๋ฆฌํฝ์ค๋ฅผ ๋ฌธ์์์ ์๋ตํ ์ ์๊ณ , ๋๋SwaggerModule.setup()์ ๊ฒฝ๋ก์:version๊ณผ ๊ฐ์ ๋์ ์ธ๊ทธ๋จผํธ๋ฅผ ์ฌ์ฉํด Swagger UI๋ฅผ ๊ฐ ๋ฒ์ ์ ๋ง๊ฒ ์ ๊ณตํ ์๋ ์์ต๋๋ค. ๋จ์ผ ๋ฌธ์ ์ ๊ทผ ๋ฐฉ์์์๋ ์ผ๋ฐ์ ์ผ๋ก ํ ๊ฐ์ UI์์ ๋ชจ๋ ๋ฒ์ ์ ๋ณด์ฌ์ฃผ์ง๋ง, ํ์์ ๋ฐ๋ผ ์ด๋ฌํ ์ค์ ์ผ๋ก Swagger UI ์ ๊ทผ ๊ฒฝ๋ก๋ฅผ ํ๋ํ ์ ์์ต๋๋ค.
Swagger ์ค์ - ๋ค์ค ๋ฌธ์ ๋ถ๋ฆฌ
API ๊ท๋ชจ๊ฐ ์ปค์ง๊ฑฐ๋, ๋ชจ๋
ธ๋ ํฌ(monorepo) ๊ตฌ์กฐ๋ก ์ฌ๋ฌ ๋ชจ๋์ด ๊ณต์กดํ๋ ๊ฒฝ์ฐ ํน์ ๋ง์ดํฌ๋ก์๋น์ค ๊ฒฝ๊ณ๋ฅผ ๋๋ ๋ณ๋์ API ๋ฌธ์๋ฅผ ๊ด๋ฆฌํด์ผ ํ๋ ๊ฒฝ์ฐ์๋ "๋ค์ค Swagger ๋ฌธ์" ์ ๋ต์ด ์ ์ฉํฉ๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์์๋ API ๋ฒ์ ๋ณ ๋๋ ๋ชจ๋๋ณ๋ก ๋ณ๋์ Swagger ์คํ๊ณผ UI๋ฅผ ๋ง๋ค์ด ์ ๊ณตํฉ๋๋ค. ์๋ฅผ ๋ค์ด, v1 API๋ /v1/docs์์ ๋ฌธ์ํํ๊ณ v2 API๋ /v2/docs์์ ๋ณ๋ UI๋ก ์ ๊ณตํ ์ ์์ต๋๋ค (ํน์ ์์ฝ ์๋น์ค์ ๊ฒฐ์ ์๋น์ค๋ฅผ ๊ฐ๊ฐ ๋ค๋ฅธ ๋ฌธ์๋ก ๋
ธ์ถํ๋ ์์ผ๋ก ๋ชจ๋๋ณ ๋ถ๋ฆฌ๋ ๊ฐ๋ฅ). ์ด๋ ๊ฒ ํ๋ฉด ํน์ ๋ฒ์ ์ด๋ ๋๋ฉ์ธ์ ํด๋นํ๋ ์๋ํฌ์ธํธ๋ง ์ ๋ณํ์ฌ ๋ฌธ์ํํ ์ ์์ด ๋ฌธ์๊ฐ ๋ฐฉ๋ํด์ง๋ ๊ฒ์ ๋ฐฉ์งํ๊ณ ๊ด๋ฆฌ ํฌ์ธํธ๋ฅผ ๋ถ๋ฆฌํ ์ ์์ต๋๋ค.
NestJS Swagger ๋ชจ๋์ ์ด๋ฌํ ๋ค์ค ๋ช
์ธ ์ง์์ ๊ธฐ๋ณธ ์ ๊ณตํ๋๋ฐ, ์ด๋ฅผ ์ํด ์ ํ๋ฆฌ์ผ์ด์
์ ๋ชจ๋ํํ๊ณ SwaggerModule.createDocument() ํธ์ถ ์ include ์ต์
์ ํ์ฉํ๋ฉด ๋ฉ๋๋ค. createDocument์ ์ธ ๋ฒ์งธ ์ธ์๋ก SwaggerDocumentOptions ๊ฐ์ฒด๋ฅผ ์ ๋ฌํ์ฌ, ๊ทธ ์์ ํฌํจ์ํฌ ๋ชจ๋ ๋ชฉ๋ก์ include ๋ฐฐ์ด๋ก ์ง์ ํ๋ฉด ํด๋น ๋ชจ๋๋ค์ ์ํ ๊ฒฝ๋ก๋ง์ ์ค์บํ์ฌ ๋ฌธ์๋ฅผ ์์ฑํฉ๋๋ค. ๊ณต์ ๋ฌธ์์ ์์ ๋ฅผ ๋ณด๋ฉด CatsModule๊ณผ DogsModule์ ๊ฐ๋ณ ํฌํจํ์ฌ ๋ ๊ฐ์ ์คํ์ ๋ง๋ค๊ณ , ๊ฐ๊ฐ ๋ณ๋์ Swagger UI ์๋ํฌ์ธํธ์ ๋
ธ์ถํ ์ ์๋ค๊ณ ์ค๋ช
ํฉ๋๋ค.
๋ค์์ ๋ฒ์ ๋ณ๋ก ๋ชจ๋์ ๋ถ๋ฆฌํ์ฌ Swagger ๋ฌธ์๋ฅผ ์์ฑํ๋ ์ฝ๋ ์์์ ๋๋ค:
// ์์: v1, v2 ๋ชจ๋์ด ๋ถ๋ฆฌ๋ ๊ฒฝ์ฐ์ Swagger ๋ฌธ์ ์ค์
import { ReservationsModuleV1 } from './reservations-v1.module';
import { ReservationsModuleV2 } from './reservations-v2.module';
// ... (NestFactory๋ก app ์์ฑ ๋ฑ์ ์๋ต)
const v1Config = new DocumentBuilder()
.setTitle('Reservation API - v1')
.setDescription('Reservation API (๋ฒ์ 1)')
.setVersion('1.0')
.build();
// v1 ๋ชจ๋๋ง ํฌํจํ Swagger ๋ฌธ์ ์์ฑ
const documentV1 = SwaggerModule.createDocument(app, v1Config, {
include: [ReservationsModuleV1],
});
SwaggerModule.setup('api/v1/docs', app, documentV1); // v1 ๋ฌธ์ UI ์๋ํฌ์ธํธ
const v2Config = new DocumentBuilder()
.setTitle('Reservation API - v2')
.setDescription('Reservation API (๋ฒ์ 2)')
.setVersion('2.0')
.build();
// v2 ๋ชจ๋๋ง ํฌํจํ Swagger ๋ฌธ์ ์์ฑ
const documentV2 = SwaggerModule.createDocument(app, v2Config, {
include: [ReservationsModuleV2],
});
SwaggerModule.setup('api/v2/docs', app, documentV2); // v2 ๋ฌธ์ UI ์๋ํฌ์ธํธ
์ ์ฝ๋์์๋ ReservationsModuleV1๊ณผ ReservationsModuleV2 ๋ ๋ชจ๋์ ๊ฐ์ ํ๊ณ , ๊ฐ๊ฐ์ ๋ชจ๋์ ํฌํจํ๋ ๋ณ๋์ Swagger ๋ฌธ์๋ฅผ ๋ง๋ค์์ต๋๋ค. include ์ต์
์ ๋ฐฐ์ด๋ก ๋ชจ๋์ ๋๊ธฐ๋ฉด ํด๋น ๋ชจ๋ ๋ฐ ๊ทธ ํ์์ ์ฐ๊ฒฐ๋ ๋ชจ๋ ์ปจํธ๋กค๋ฌ ๊ฒฝ๋ก๋ค๋ง ๋ฐ์๋ OpenAPI ์คํ์ด ์์ฑ๋ฉ๋๋ค. ์ด๋ ๊ฒ ์์ฑ๋ documentV1, documentV2๋ฅผ ์๋ก ๋ค๋ฅธ ๊ฒฝ๋ก(/api/v1/docs, /api/v2/docs)์ SwaggerModule.setup()์ผ๋ก ์ค์ ํ์ฌ, ๋ฒ์ 1์ฉ Swagger UI์ ๋ฒ์ 2์ฉ Swagger UI๋ฅผ ๋ถ๋ฆฌํด ์ ๊ณตํฉ๋๋ค. ์ด์ ํด๋ผ์ด์ธํธ๋ ๊ฐ๋ฐ์๋ /api/v1/docs์์ v1 API๋ง, /api/v2/docs์์ v2 API๋ง ๊ฐ๊ฐ ํ์ธํ ์ ์์ต๋๋ค.
ํ: ์ด ์ ๊ทผ ๋ฐฉ์์ ๋ฒ์ ๋ฟ ์๋๋ผ ๊ธฐ๋ฅ๋ณ ๋ชจ๋๋ก ๋ฌธ์๋ฅผ ๋ถ๋ฆฌํ๋ ๊ฒฝ์ฐ์๋ ํ์ฉํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด _Public API_์ _Admin API_๋ฅผ ๊ฐ๊ฐ ๋ค๋ฅธ ๋ชจ๋๋ก ๊ด๋ฆฌํ๋ฉด์ Swagger ๋ฌธ์๋ฅผ ๋ณ๋๋ก ์ ๊ณตํ๊ฑฐ๋, ๋ง์ดํฌ๋ก์๋น์ค๋ณ๋ก ๋ฌธ์๋ฅผ ๋ฐ๋ก ์์ฑํ์ฌ ์๋น์ค ๊ฒฝ๊ณ๋ง๋ค ๋ฌธ์๋ฅผ ์ฐธ์กฐํ๊ฒ ํ ์ ์์ต๋๋ค.
include์ต์ ์ ์ํ๋ ๋ชจ๋ ์กฐํฉ์ ๋๊ธฐ๋ฉด ํ์ํ ์๋ํฌ์ธํธ ๊ทธ๋ฃน๋ง ๋ฌธ์ํํ ์ ์์ต๋๋ค.
๊ฐ ์ ๊ทผ ๋ฐฉ์์ ํ์ฉ ์๋๋ฆฌ์ค
์์ ์ดํด๋ณธ ๋จ์ผ ๋ฌธ์ ํตํฉ๊ณผ ๋ค์ค ๋ฌธ์ ๋ถ๋ฆฌ ๋ ๊ฐ์ง Swagger ํตํฉ ์ ๋ต์ ๊ฐ๊ฐ ์ฅ๋จ์ ์ด ์์ผ๋ฉฐ, ์ฌ์ฉํ ์ํฉ์ด ๋ค๋ฆ ๋๋ค. ํ๋ก์ ํธ์ ๊ท๋ชจ์ ์๊ตฌ ์ฌํญ์ ๋ฐ๋ผ ์๋ง์ ๋ฐฉ์์ ์ ํํ๋ฉด ๋ฉ๋๋ค:
-
๋จ์ผ Swagger ๋ฌธ์: API ๊ท๋ชจ๊ฐ ํฌ์ง ์๊ฑฐ๋ ๋ชจ๋ ๋ฒ์ ์ ์๋ํฌ์ธํธ๋ฅผ ํ ๊ณณ์์ ๊ด๋ฆฌํ๊ณ ์ ํ ๋ ์ ํฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์๊ท๋ชจ ์๋น์ค์์๋ v1๊ณผ v2๋ฅผ ๊ตณ์ด ๋ถ๋ฆฌํ์ง ์๊ณ ํ ๋ฒ์ ๋ณด์ฌ์ฃผ๋ ํธ์ด ๊ฐ๋ฐ์์๊ฒ ํธ๋ฆฌํ ์ ์์ต๋๋ค. ํ ๊ฐ์ Swagger UI์์ ์ ์ฒด API ์คํ์ ์กฐํํ ์ ์์ด ๊ฒ์๊ณผ ์ฐธ์กฐ๊ฐ ์ฝ๊ณ , ์ค์ ๋ ๋น๊ต์ ๋จ์ํฉ๋๋ค. ๋ฒ์ ๊ฐ ๋ณํ๊ฐ ๋น๊ต์ ์ ๊ฑฐ๋, ํ ๋ฌธ์์์ ๋ฒ์ ๋ณ ๊ฒฝ๋ก๋ง ๊ตฌ๋ถํ๋ฉด ์ถฉ๋ถํ ๊ฒฝ์ฐ์ ์ ์ฉํฉ๋๋ค. (NestJS์ URI ๋ฒ์ ๋ ์ ์ฉ๋ง์ผ๋ก Swagger์ ๊ฐ ๊ฒฝ๋ก๊ฐ
/v1/,/v2/์ฒ๋ผ ํ์๋๋ฏ๋ก ํ๋์ ๋ฒ์ ์ ๊ตฌ๋ถํ ์ ์์ต๋๋ค.) -
๋ค์ค Swagger ๋ฌธ์: ๋๊ท๋ชจ ๋ชจ๋๋ฆฌ์ ๋๋ ๋ชจ๋ ธ๋ ํฌ ํ๋ก์ ํธ์์ ๋ชจ๋๋ณ๋ก API๊ฐ ๋ฐฉ๋ํ๊ฒ ์กด์ฌํ๋ ๊ฒฝ์ฐ๋, ๋ง์ดํฌ๋ก์๋น์ค ๊ฒฝ๊ณ๋ฅผ ๋ช ํํ ๋๋์ด ๋ฌธ์ํํด์ผ ํ ๊ฒฝ์ฐ ์ ์ฉํฉ๋๋ค. ๋ํ API ๋ฒ์ ์ ๊ฐ๋ณ์ ์ผ๋ก ๋ฐฐํฌํ๊ฑฐ๋ ๊ด๋ฆฌํ๋ ์๋๋ฆฌ์ค์์๋ ๊ฐ ๋ฒ์ ๋ณ๋ก ๋ฌธ์๋ฅผ ๋ถ๋ฆฌํ๋ฉด ํผ์ ์ ์ค์ผ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด v2๋ฅผ ๊ฐ๋ฐ ์ค์ธ ๋์ v1 ๋ฌธ์๋ ์์ ์ ์ผ๋ก ๋ณ๋ ์ ๊ณตํ๊ณ , ์ค๋น๋๋ฉด v2 ๋ฌธ์๋ฅผ ๊ณต๊ฐํ๋ ์ ๋ต์ ์ทจํ ์ ์์ต๋๋ค. ์ด ๋ฐฉ์์ ๊ฐ ๋ฌธ์๊ฐ ๊ฒฝ๋ํ๋์ด ๋ก๋ ์๋๊ฐ ๋นจ๋ผ์ง๊ณ ๊ฐ๋ ์ฑ์ด ํฅ์๋๋ฉฐ, ๊ถํ ์ ์ด๋ ๋ฒ์ ๋ณ๋ก ๋ถ๋ฆฌํ๊ธฐ๊ฐ ์์ํฉ๋๋ค (์: ๋ด๋ถ API ๋ฌธ์๋ ๋ด๋ถ์ฉ์ผ๋ก๋ง ๋ ธ์ถํ๊ณ ๊ณต๊ฐ API ๋ฌธ์๋ ๋ฐ๋ก ๋ถ๋ฆฌ).
์์ฝํ๋ฉด, ์์ ๊ท๋ชจ๋ ๋จ์ผ ์๋น์ค๋ผ๋ฉด ๋ชจ๋ ๋ฒ์ ์ ํ๋์ Swagger ๋ฌธ์๋ก ๊ด๋ฆฌํ๋ ํธ์ด ๊ฐํธํ๋ฉฐ, ๋๊ท๋ชจ ์๋น์ค๋ ๋ค์์ ๋ชจ๋์ ๊ฐ๋ ๊ฒฝ์ฐ์๋ ๋ฒ์ /๋ชจ๋๋ณ๋ก Swagger ๋ฌธ์๋ฅผ ๋ถ๋ฆฌํ์ฌ ์ ์ง๋ณด์์ฑ๊ณผ ๋ช ํ์ฑ์ ๋์ด๋ ๊ฒ์ด ์ข์ต๋๋ค. ๋ ์ ๊ทผ ๋ฐฉ์ ๋ชจ๋ NestJS์์ ๊ณต์์ ์ผ๋ก ์ง์๋๋ฏ๋ก, ํ์์ ๋ฐ๋ผ ์ ์ ํ ์ ํํ์ฌ ํ์ฉํ๋ฉด ๋ฉ๋๋ค.
๊ฐ ๋ฐฉ๋ฒ์ ๊ตฌํํ๋ ์ฝ๋๋ ์์์ ์ดํด๋ณธ ๋๋ก ๋น๊ต์ ๊ฐ๋จํ๋ฉฐ, NestJS์ ๋ฒ์ ๊ด๋ฆฌ ๋ฐ Swagger ๋ชจ๋ ๊ธฐ๋ฅ์ ์กฐํฉํ์ฌ ์ ์ฐํ๊ฒ API ๋ฌธ์๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ๋ง ํ๋ค๋ฉด, NestJS๋ ๋ฒ์ ๋ณ๋ก ํธํ์ฑ ์ ์ง์ ๋ฌธ์ํ๋ฅผ ์์ฝ๊ฒ ์ง์ํ๋ฏ๋ก, ์์ฌํ๊ณ API๋ฅผ ๋ฐ์ ์์ผ ๋๊ฐ ์ ์์ ๊ฒ์ ๋๋ค.
์ฐธ๊ณ ์๋ฃ: NestJS ๊ณต์ ๋ฌธ์ ๋ฐ GitHub ์ด์ ๋ฑ์ ํตํด API ๋ฒ์ ๋ ๋ฐ Swagger ํตํฉ์ ๋ํ ์ถ๊ฐ ์ ๋ณด๋ฅผ ์ป์ ์ ์์ต๋๋ค. (์: NestJS Docs - Versioning, OpenAPI/Swagger ์น์ ) ์ด๋ฒ ๊ฐ์ด๋์์ ๋ค๋ฃฌ ๋ด์ฉ์ ํ์ ์์๋ ๋ง์ด ์ฌ์ฉํ๋ ํจํด์ผ๋ก, NestJS ๊ธฐ๋ฐ ํ๋ก์ ํธ์ API ์ค๊ณ์ ๋ฌธ์ ์ ๋ต ์๋ฆฝ์ ๋์์ด ๋๊ธธ ๋ฐ๋๋๋ค.